﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Linq.Expressions;

namespace Warehouse.DataAccess
{
    public class CustomView<TEntity> where TEntity : class
    {
        public static List<TEntity> GetList()
        {
            return GetList(null);
        }

        public static List<TEntity> GetList(Expression<Func<TEntity, bool>> predicate)
        {
            using (WarehouseClassesDataContext context = new WarehouseClassesDataContext())
            {
                if (predicate != null)
                {
                    return context.GetTable<TEntity>().Where(predicate).ToList();
                }
                else
                {
                    return context.GetTable<TEntity>().ToList();
                }
            }
        }

        public static TEntity GetSingle(Expression<Func<TEntity, bool>> predicate)
        {
            using (WarehouseClassesDataContext context = new WarehouseClassesDataContext())
            {
                return context.GetTable<TEntity>().Where(predicate).SingleOrDefault();
            }
        }

        public static TEntity GetFirst(Expression<Func<TEntity, bool>> predicate)
        {
            using (WarehouseClassesDataContext context = new WarehouseClassesDataContext())
            {
                return context.GetTable<TEntity>().Where(predicate).FirstOrDefault();
            }
        }

        public static TEntity GetOne(Expression<Func<TEntity, bool>> predicate)
        {
            return GetFirst(predicate);
        }
    }

    public abstract class CustomeEntity<TEntity> : CustomView<TEntity> where TEntity : class
    {
        static Dictionary<Type, System.Reflection.PropertyInfo[]> sDicProperties = new Dictionary<Type, System.Reflection.PropertyInfo[]>();

        #region Static Methods

        public static void CopyData(TEntity source, TEntity target)
        {
            PropertyInfo[] properties = null;
            lock (sDicProperties)
            {
                Type tp = typeof(TEntity);
                if (sDicProperties.ContainsKey(tp))
                {
                    properties = sDicProperties[tp];
                }
                else
                {
                    var propertyArr = tp.GetProperties();
                    properties = propertyArr.Where(p => p.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute), true).Length > 0).ToArray();
                    sDicProperties.Add(tp, properties);
                }
            }
            foreach (var p in properties)
            {
                object v = p.GetValue(source, null);
                p.SetValue(target, v, null);
            }
        }

        public static TEntity GetOne(Expression<Func<TEntity, bool>> predicate)
        {
            using (WarehouseClassesDataContext context = new WarehouseClassesDataContext())
            {
                return context.GetTable<TEntity>().Where(predicate).FirstOrDefault();
            }
        }

        #endregion

        #region Instance Methods

        /// <summary>
        /// 获取数据库唯一记录（通常根据主键判断）
        /// </summary>
        /// <returns></returns>
        protected abstract Expression<Func<TEntity, bool>> GetPredicate();

        protected virtual TEntity GetRecord(System.Data.Linq.Table<TEntity> table)
        {
            return table.SingleOrDefault(this.GetPredicate());
        }

        public virtual void Save()
        {
            using (WarehouseClassesDataContext context = new WarehouseClassesDataContext())
            {
                Save(context);
            }
        }

        public virtual void Save(WarehouseClassesDataContext context)
        {
            TEntity data = this as TEntity;

            System.Data.Linq.Table<TEntity> table = context.GetTable<TEntity>();
            TEntity record = GetRecord(table);
            if (record != null)
            {
                CopyData(data, record);
                context.SubmitChanges();
                CopyData(record, data);
            }
            else
            {
                table.InsertOnSubmit(data);
                context.SubmitChanges();
            }
        }

        public virtual void Delete()
        {
            TEntity data = this as TEntity;
            using (WarehouseClassesDataContext context = new WarehouseClassesDataContext())
            {
                System.Data.Linq.Table<TEntity> table = context.GetTable<TEntity>();
                TEntity record = GetRecord(table);
                if (record != null)
                {
                    table.DeleteOnSubmit(record);
                    context.SubmitChanges();
                }
            }
        }

        #endregion
    }

    public enum BillStatus
    {
        Default = 0,
        Invalid = 1
    }
}
